"""
简化的CP-SAT求解器模块

实现简化的项目调度优化求解器，移除复杂的约束逻辑，
统一处理所有工序类型，支持动态资源约束添加。
"""

import time
from dataclasses import dataclass
from typing import Any, Dict, List, Optional, Tuple

from ortools.sat.python import cp_model

from .data_models import SolverResult
from .exceptions import ModelingError, SolvingError, WorkerCapacityError
from .logging_config import get_logger

# 初始化日志记录器
logger = get_logger("cpsat_solver")
from .subdivision_processor import SubdivisionProcessor, SubdivisionError


@dataclass
class SimplifiedSolverResult:
    """简化的求解结果数据类"""

    status: str
    makespan: Optional[int] = None
    schedule: Optional[Dict[int, Dict[str, Any]]] = None
    solve_time: Optional[float] = None
    error_message: Optional[str] = None
    worker_allocation: Optional[Dict[int, Dict[str, int]]] = None
    subdivision_info: Optional[Dict[str, Any]] = None


class SimplifiedCPSATSolver:
    """简化的CP-SAT求解器

    移除复杂的约束逻辑和工序分类处理，实现统一的工序处理逻辑。
    专注于核心的调度优化功能。
    """

    def __init__(self):
        """初始化求解器"""
        self.model: Optional[cp_model.CpModel] = None
        self.solver: Optional[cp_model.CpSolver] = None
        self.activity_vars: Optional[Dict[int, Dict[str, Any]]] = None

    def solve(
        self, project_data: Dict[str, Any], config: Dict[str, Any]
    ) -> SimplifiedSolverResult:
        """
        使用CP-SAT求解调度问题

        Args:
            project_data: 项目数据，包含activities、precedences、resources、resource_demands
            config: 求解配置参数

        Returns:
            求解结果

        Raises:
            ModelingError: 模型构建错误
            SolvingError: 求解过程错误
        """
        start_time = time.time()
        subdivision_info = None

        try:
            # 1. 验证输入数据
            self._validate_project_data(project_data)

            # 2. 处理分区（如果启用）
            processed_project_data, subdivision_info = self._process_subdivision(project_data, config)

            # 3. 构建CP-SAT模型
            self._build_model(processed_project_data, config)

            # 4. 求解模型
            result = self._solve_model(config)

            # 5. 处理求解结果
            if result.status in ["OPTIMAL", "FEASIBLE"]:
                result.schedule = self._extract_schedule(processed_project_data)
                result.worker_allocation = self._extract_worker_allocation(processed_project_data)
                result.subdivision_info = subdivision_info

            result.solve_time = time.time() - start_time
            return result

        except Exception as e:
            solve_time = time.time() - start_time
            if isinstance(e, (ModelingError, SolvingError, SubdivisionError)):
                return SimplifiedSolverResult(
                    status="ERROR", 
                    error_message=str(e), 
                    solve_time=solve_time,
                    subdivision_info=subdivision_info
                )
            else:
                return SimplifiedSolverResult(
                    status="ERROR",
                    error_message=f"求解过程发生未知错误: {str(e)}",
                    solve_time=solve_time,
                    subdivision_info=subdivision_info
                )

    def _validate_project_data(self, project_data: Dict[str, Any]) -> None:
        """验证项目数据完整性"""
        required_keys = ["activities", "precedences", "resources", "resource_demands"]

        for key in required_keys:
            if key not in project_data:
                raise ModelingError(f"缺少必需的数据字段: {key}")

        activities = project_data["activities"]
        if not activities:
            raise ModelingError("工序列表不能为空")

        # 验证工序数据
        for activity in activities:
            if "id" not in activity or "duration" not in activity:
                raise ModelingError(f"工序数据不完整: {activity}")

            if activity["duration"] <= 0:
                raise ModelingError(f"工序 {activity['id']} 的工期必须大于0")
        
        # 验证工种需求数据
        worker_requirements = project_data.get("worker_requirements", {})
        if worker_requirements:
            self._validate_worker_requirements(worker_requirements, activities)

    def _build_model(
        self, project_data: Dict[str, Any], config: Dict[str, Any]
    ) -> None:
        """构建CP-SAT模型"""
        try:
            # 创建CP-SAT模型
            self.model = cp_model.CpModel()

            # 提取数据
            activities = project_data["activities"]
            precedences = project_data["precedences"]
            resources = project_data["resources"]
            resource_demands = project_data["resource_demands"]

            # 计算时间窗口上界
            horizon = self._calculate_horizon(activities)

            # 创建工序变量（统一处理所有工序）
            self.activity_vars = self._create_activity_variables(activities, horizon)

            # 添加前置关系约束
            self._add_precedence_constraints(precedences)

            # 添加资源约束（支持动态资源类型）
            self._add_resource_constraints(resources, resource_demands, activities)
            
            # 添加工种约束 - 增强版本
            worker_requirements = project_data.get("worker_requirements", {})
            
            # 获取工种容量配置（增强版本）
            try:
                worker_capacities = self._get_worker_capacities(project_data, config)
                logger.info(f"成功获取工种容量配置: {len(worker_capacities)} 种工人")
            except Exception as e:
                logger.error(f"获取工种容量配置失败: {e}")
                worker_capacities = {}
            
            logger.info(f"约束检查 - Worker requirements 条目数: {len(worker_requirements)}")
            logger.info(f"约束检查 - Worker capacities 种类数: {len(worker_capacities)}")
            
            # 应用工种约束
            if worker_requirements and worker_capacities:
                try:
                    logger.info("开始应用工种约束")
                    self._add_worker_constraints(worker_requirements, worker_capacities, activities)
                    logger.info("工种约束应用完成")
                except Exception as e:
                    logger.error(f"应用工种约束失败: {e}")
                    # 不抛出异常，继续构建其他约束
                    logger.warning("工种约束应用失败，继续构建其他约束")
            else:
                logger.info(f"跳过工种约束: requirements={len(worker_requirements)}, capacities={len(worker_capacities)}")
                if not worker_requirements:
                    logger.info("跳过工种约束：没有工种需求数据")
                if not worker_capacities:
                    logger.warning("跳过工种约束：没有工种容量配置")

            # 设置优化目标
            self._set_objective()

        except Exception as e:
            raise ModelingError(f"模型构建失败: {str(e)}")

    def _create_activity_variables(
        self, activities: List[Dict[str, Any]], horizon: int
    ) -> Dict[int, Dict[str, Any]]:
        """
        创建工序变量（统一处理逻辑）

        为每个工序创建开始时间、结束时间和区间变量，
        不区分工序类型，统一处理所有工序。

        Args:
            activities: 工序列表
            horizon: 时间窗口上界

        Returns:
            包含所有工序变量的字典
        """
        if self.model is None:
            raise ModelingError("模型未初始化")

        activity_vars = {}

        for activity in activities:
            activity_id = activity["id"]
            duration = activity["duration"]

            # 创建开始时间变量
            start_var = self.model.NewIntVar(0, horizon, f"start_{activity_id}")

            # 创建结束时间变量
            end_var = self.model.NewIntVar(0, horizon, f"end_{activity_id}")

            # 添加持续时间约束: end = start + duration
            self.model.Add(end_var == start_var + duration)

            # 创建区间变量（用于资源约束）
            interval_var = self.model.NewIntervalVar(
                start_var, duration, end_var, f"interval_{activity_id}"
            )

            activity_vars[activity_id] = {
                "start": start_var,
                "end": end_var,
                "interval": interval_var,
                "duration": duration,
            }

        return activity_vars

    def _add_precedence_constraints(self, precedences: List[Dict[str, Any]]) -> None:
        """
        添加前置关系约束（保持原有逻辑）

        支持四种依赖类型：FS, SS, FF, SF

        Args:
            precedences: 前置关系列表
        """
        if self.model is None or self.activity_vars is None:
            raise ModelingError("模型或工序变量未初始化")

        for precedence in precedences:
            from_id = precedence["from"]
            to_id = precedence["to"]
            dep_type = precedence["type"]
            lag = precedence["lag"]

            # 验证工序ID存在
            if from_id not in self.activity_vars:
                raise ModelingError(f"前置工序 {from_id} 不存在")
            if to_id not in self.activity_vars:
                raise ModelingError(f"后续工序 {to_id} 不存在")

            pred_vars = self.activity_vars[from_id]
            succ_vars = self.activity_vars[to_id]

            # 根据依赖类型添加约束
            if dep_type == "FS":
                # Finish-to-Start: 后续开始时间 >= 前置结束时间 + 延时
                self.model.Add(succ_vars["start"] >= pred_vars["end"] + lag)
            elif dep_type == "SS":
                # Start-to-Start: 后续开始时间 >= 前置开始时间 + 延时
                self.model.Add(succ_vars["start"] >= pred_vars["start"] + lag)
            elif dep_type == "FF":
                # Finish-to-Finish: 后续结束时间 >= 前置结束时间 + 延时
                self.model.Add(succ_vars["end"] >= pred_vars["end"] + lag)
            elif dep_type == "SF":
                # Start-to-Finish: 后续结束时间 >= 前置开始时间 + 延时
                self.model.Add(succ_vars["end"] >= pred_vars["start"] + lag)
            else:
                raise ModelingError(f"不支持的依赖类型: {dep_type}")

    def _add_resource_constraints(
        self,
        resources: Dict[str, int],
        resource_demands: Dict[str, Dict[str, int]],
        activities: List[Dict[str, Any]],
    ) -> None:
        """
        添加资源约束（支持动态资源约束添加）

        为每种资源类型添加Cumulative约束，支持动态识别和处理
        不同类型的资源。

        Args:
            resources: 可用资源字典 {resource_type: capacity}
            resource_demands: 资源需求字典 {activity_id: {resource_type: demand}}
            activities: 工序列表
        """
        if self.model is None or self.activity_vars is None:
            raise ModelingError("模型或工序变量未初始化")

        # 为每种资源类型添加约束
        for resource_type, capacity in resources.items():
            intervals = []
            demands = []

            # 收集使用该资源的工序
            for activity in activities:
                activity_id = str(activity["id"])

                # 检查该工序是否需要此资源
                if activity_id in resource_demands:
                    demand = resource_demands[activity_id].get(resource_type, 0)

                    if demand > 0:
                        # 验证需求不超过总容量
                        if demand > capacity:
                            raise ModelingError(
                                f"工序 {activity_id} 对资源 {resource_type} 的需求 ({demand}) "
                                f"超过了可用容量 ({capacity})"
                            )

                        intervals.append(self.activity_vars[activity["id"]]["interval"])
                        demands.append(demand)

            # 如果有工序使用该资源，添加累积约束
            if intervals:
                self.model.AddCumulative(intervals, demands, capacity)

    def _set_objective(self) -> None:
        """
        设置优化目标

        最小化总工期（makespan）- 所有工序中最晚的结束时间
        """
        if self.model is None or self.activity_vars is None:
            raise ModelingError("模型或工序变量未初始化")

        # 创建makespan变量，它必须大于等于所有工序的结束时间
        makespan = self.model.NewIntVar(0, 10000, "makespan")

        # 添加约束：makespan >= 每个工序的结束时间
        for activity_id, vars_dict in self.activity_vars.items():
            self.model.Add(makespan >= vars_dict["end"])

        # 设置优化目标：最小化makespan
        self.model.Minimize(makespan)

    def _calculate_horizon(self, activities: List[Dict[str, Any]]) -> int:
        """
        计算时间窗口上界

        使用所有工序工期之和作为保守估计

        Args:
            activities: 工序列表

        Returns:
            时间窗口上界
        """
        total_duration = sum(activity["duration"] for activity in activities)
        # 添加一些缓冲，确保有足够的时间窗口
        buffer = max(10, total_duration // 10)
        horizon = total_duration + buffer
        return int(horizon)

    def _solve_model(self, config: Dict[str, Any]) -> SimplifiedSolverResult:
        """
        求解CP-SAT模型

        Args:
            config: 求解配置参数

        Returns:
            求解结果
        """
        if self.model is None:
            raise ModelingError("模型未初始化")

        try:
            # 创建求解器
            self.solver = cp_model.CpSolver()

            # 配置求解器参数
            self._configure_solver_parameters(config)

            # 求解模型
            status = self.solver.Solve(self.model)

            # 处理求解结果
            return self._process_solve_result(status)

        except Exception as e:
            raise SolvingError(f"求解过程失败: {str(e)}")

    def _configure_solver_parameters(self, config: Dict[str, Any]) -> None:
        """
        配置求解器参数

        Args:
            config: 配置参数字典
        """
        if self.solver is None:
            raise SolvingError("求解器未初始化")

        # 设置时间限制
        solve_time_limit = config.get("solve_time_limit", 300)
        self.solver.parameters.max_time_in_seconds = solve_time_limit

        # 设置其他参数
        if "num_search_workers" in config:
            self.solver.parameters.num_search_workers = config["num_search_workers"]

        if "log_search_progress" in config:
            self.solver.parameters.log_search_progress = config["log_search_progress"]

        if "random_seed" in config:
            self.solver.parameters.random_seed = config["random_seed"]

    def _process_solve_result(self, status: int) -> SimplifiedSolverResult:
        """
        处理求解结果

        Args:
            status: CP-SAT求解状态

        Returns:
            格式化的求解结果
        """
        if self.solver is None:
            raise SolvingError("求解器未初始化")

        # 状态映射
        status_map = {
            cp_model.OPTIMAL: "OPTIMAL",
            cp_model.FEASIBLE: "FEASIBLE",
            cp_model.INFEASIBLE: "INFEASIBLE",
            cp_model.MODEL_INVALID: "MODEL_INVALID",
            cp_model.UNKNOWN: "UNKNOWN",
        }

        status_str = status_map.get(status, "UNKNOWN")

        # 如果有可行解，获取目标值
        if status in [cp_model.OPTIMAL, cp_model.FEASIBLE]:
            makespan = int(self.solver.ObjectiveValue())

            return SimplifiedSolverResult(status=status_str, makespan=makespan)
        else:
            # 无解或其他错误状态
            error_messages = {
                "INFEASIBLE": "问题无解，请检查约束条件是否过于严格",
                "MODEL_INVALID": "模型构建错误，请检查输入数据",
                "UNKNOWN": "求解器无法确定问题状态",
            }

            return SimplifiedSolverResult(
                status=status_str,
                error_message=error_messages.get(status_str, "未知错误"),
            )

    def _extract_schedule(
        self, project_data: Dict[str, Any]
    ) -> Dict[int, Dict[str, Any]]:
        """
        提取调度结果

        从CP-SAT求解器中提取每个工序的调度信息

        Args:
            project_data: 项目数据

        Returns:
            详细的调度结果字典
        """
        if self.solver is None or self.activity_vars is None:
            raise SolvingError("求解器或工序变量未初始化")

        schedule = {}
        activities = project_data["activities"]
        resource_demands = project_data["resource_demands"]

        # 创建活动ID到名称的映射
        activity_names = {
            activity["id"]: activity.get("name", f'Activity_{activity["id"]}')
            for activity in activities
        }

        for activity_id, vars_dict in self.activity_vars.items():
            start_time = self.solver.Value(vars_dict["start"])
            end_time = self.solver.Value(vars_dict["end"])
            duration = vars_dict["duration"]

            # 获取资源需求信息
            activity_id_str = str(activity_id)
            resource_info = resource_demands.get(activity_id_str, {})
            resource_str = ", ".join(
                [f"{k}:{v}" for k, v in resource_info.items() if v > 0]
            )
            
            # 获取工种需求信息
            worker_requirements = project_data.get("worker_requirements", {})
            worker_info = worker_requirements.get(activity_id_str, {})
            worker_str = ", ".join(
                [f"{k}:{v}" for k, v in worker_info.items() if v > 0]
            )

            # 查找对应的活动数据以获取分区信息
            activity_data = None
            for act in activities:
                if act["id"] == activity_id:
                    activity_data = act
                    break
            
            schedule[activity_id] = {
                "id": activity_id,
                "name": activity_names.get(activity_id, f"Activity_{activity_id}"),
                "start_time": start_time,
                "end_time": end_time,
                "duration": duration,
                "resource_info": resource_str,
                "worker_info": worker_str,
                "worker_assignments": worker_info,  # 前端期望的字段名
                "worker_requirements": worker_info,  # 保留原字段名以兼容
                "can_subdivide": activity_data.get("can_subdivide", False) if activity_data else False,
                "subdivided": activity_data.get("subdivided", False) if activity_data else False,
                "original_duration": activity_data.get("original_duration", duration) if activity_data else duration,
                "predecessors": activity_data.get("predecessors", []) if activity_data else [],
            }

        return schedule
    
    def _validate_worker_requirements(
        self, 
        worker_requirements: Dict[str, Dict[str, int]], 
        activities: List[Dict[str, Any]]
    ) -> None:
        """
        验证工种需求数据
        
        Args:
            worker_requirements: 工种需求字典
            activities: 工序列表
        """
        activity_ids = {str(activity["id"]) for activity in activities}
        
        for activity_id, requirements in worker_requirements.items():
            if activity_id not in activity_ids:
                raise ModelingError(f"工种需求中引用了不存在的工序ID: {activity_id}")
                
            for worker_type, count in requirements.items():
                if not isinstance(count, int) or count <= 0:
                    raise ModelingError(
                        f"工序 {activity_id} 的工种 '{worker_type}' 需求数量必须为正整数"
                    )
    
    def _add_worker_constraints(
        self,
        worker_requirements: Dict[str, Dict[str, int]],
        worker_capacities: Dict[str, int],
        activities: List[Dict[str, Any]]
    ) -> None:
        """
        添加工种约束 - 增强版本，支持容量自动调整和详细错误处理
        
        Args:
            worker_requirements: 工种需求字典 {activity_id: {worker_type: count}}
            worker_capacities: 工种容量字典 {worker_type: capacity}
            activities: 工序列表
        """
        if self.model is None or self.activity_vars is None:
            raise ModelingError("模型或工序变量未初始化")
        
        logger.info(f"开始添加工种约束")
        logger.info(f"工种容量配置: {worker_capacities}")
        logger.info(f"工种需求数据: {len(worker_requirements)} 个工序")
        
        # 验证输入参数
        if not worker_capacities:
            logger.warning("工种容量配置为空，跳过工种约束")
            return
            
        if not worker_requirements:
            logger.warning("工种需求数据为空，跳过工种约束")
            return
        
        # 统计每种工种的使用情况
        worker_usage = {}
        adjusted_capacities = worker_capacities.copy()
        constraint_added_count = 0
        
        # 为每种工种添加容量约束
        for worker_type, capacity in worker_capacities.items():
            intervals = []
            demands = []
            max_single_demand = 0
            activity_details = []
            
            logger.info(f"处理工种: {worker_type}, 容量: {capacity}")
            
            # 收集使用该工种的工序
            for activity in activities:
                activity_id = str(activity["id"])
                
                if activity_id in worker_requirements:
                    demand = worker_requirements[activity_id].get(worker_type, 0)
                    
                    if demand > 0:
                        activity_name = activity.get('name', f'ID{activity["id"]}')
                        logger.info(f"  工序 {activity_id}({activity_name}) 需要 {worker_type}: {demand} 人")
                        
                        max_single_demand = max(max_single_demand, demand)
                        intervals.append(self.activity_vars[activity["id"]]["interval"])
                        demands.append(demand)
                        
                        activity_details.append({
                            "activity_id": activity_id,
                            "activity_name": activity_name,
                            "demand": demand
                        })
            
            # 如果有工序使用该工种，添加累积约束
            if intervals:
                # 检查是否需要调整容量
                final_capacity = capacity
                if max_single_demand > capacity:
                    if capacity == 0:
                        # 如果原容量为0，设置为最大需求
                        final_capacity = max_single_demand
                        logger.warning(f"工种 {worker_type} 原容量为0，自动设置为最大需求: {final_capacity}")
                    else:
                        # 自动调整容量以满足最大单个需求
                        final_capacity = max_single_demand
                        logger.warning(f"工种 {worker_type} 容量不足，自动调整: {capacity} -> {final_capacity}")
                        logger.warning(f"原因: 工序的最大单个需求 ({max_single_demand}) 超过了配置容量 ({capacity})")
                    
                    adjusted_capacities[worker_type] = final_capacity
                
                logger.info(f"为工种 {worker_type} 添加累积约束: {len(intervals)} 个工序，最终容量 {final_capacity}")
                self.model.AddCumulative(intervals, demands, final_capacity)
                constraint_added_count += 1
                
                # 统计使用情况
                worker_usage[worker_type] = {
                    "capacity": final_capacity,
                    "activities": activity_details,
                    "total_demand": sum(demands),
                    "max_single_demand": max_single_demand,
                    "activity_count": len(activity_details)
                }
            else:
                logger.info(f"工种 {worker_type} 没有被任何工序使用")
        
        # 记录容量调整信息
        adjusted_types = [wt for wt, cap in adjusted_capacities.items() 
                         if cap != worker_capacities.get(wt, 0)]
        if adjusted_types:
            logger.info(f"已自动调整以下工种容量: {adjusted_types}")
            logger.info(f"调整后的完整容量配置: {adjusted_capacities}")
        
        # 记录工种使用统计
        logger.info("工种使用统计:")
        for worker_type, usage_info in worker_usage.items():
            total_demand = usage_info["total_demand"]
            capacity = usage_info["capacity"]
            utilization = (total_demand / capacity) * 100 if capacity > 0 else 0
            logger.info(f"  {worker_type}: {total_demand}/{capacity} ({utilization:.1f}% 利用率), "
                       f"最大单次需求: {usage_info['max_single_demand']}, "
                       f"使用工序数: {usage_info['activity_count']}")
        
        logger.info(f"工种约束添加完成，共添加 {constraint_added_count} 个约束")
        
        # 检查是否有工种需求但没有对应的容量配置
        all_required_worker_types = set()
        for requirements in worker_requirements.values():
            all_required_worker_types.update(requirements.keys())
        
        missing_capacities = all_required_worker_types - set(worker_capacities.keys())
        if missing_capacities:
            logger.warning(f"以下工种有需求但没有容量配置: {missing_capacities}")
            logger.warning("这些工种的约束将被忽略，可能影响调度结果的准确性")
    
    def _get_worker_capacities(
        self, 
        project_data: Dict[str, Any], 
        config: Dict[str, Any]
    ) -> Dict[str, int]:
        """
        多源获取工种容量配置 - 增强版本
        优先级：project_data > config > 默认值
        
        Args:
            project_data: 项目数据
            config: 配置参数
            
        Returns:
            工种容量字典
        """
        logger.info("开始获取工种容量配置")
        logger.info(f"project_data keys: {list(project_data.keys())}")
        logger.info(f"config keys: {list(config.keys())}")
        
        # 1. 优先从project_data获取
        worker_capacities = project_data.get("worker_capacities", {})
        if worker_capacities and isinstance(worker_capacities, dict):
            # 验证配置格式
            validated_capacities = self._validate_and_clean_capacities(worker_capacities, "project_data")
            if validated_capacities:
                logger.info(f"从project_data获取工种容量: {validated_capacities}")
                return validated_capacities
            else:
                logger.warning("project_data中的工种容量配置无效，尝试其他来源")
        
        # 2. 从config获取
        worker_capacities = config.get("worker_capacities", {})
        if worker_capacities and isinstance(worker_capacities, dict):
            # 验证配置格式
            validated_capacities = self._validate_and_clean_capacities(worker_capacities, "config")
            if validated_capacities:
                logger.info(f"从config获取工种容量: {validated_capacities}")
                return validated_capacities
            else:
                logger.warning("config中的工种容量配置无效，使用默认配置")
        
        # 3. 检查是否有工种需求数据，如果有则基于需求生成智能默认值
        worker_requirements = project_data.get("worker_requirements", {})
        if worker_requirements:
            smart_defaults = self._generate_smart_default_capacities(worker_requirements)
            logger.info(f"基于工种需求生成智能默认容量: {smart_defaults}")
            return smart_defaults
        
        # 4. 使用标准默认值
        default_capacities = self._get_standard_default_capacities()
        logger.info(f"使用标准默认工种容量: {default_capacities}")
        return default_capacities
    
    def _validate_and_clean_capacities(
        self, 
        capacities: Dict[str, Any], 
        source: str
    ) -> Dict[str, int]:
        """
        验证和清理工种容量配置
        
        Args:
            capacities: 原始容量配置
            source: 配置来源（用于日志）
            
        Returns:
            清理后的有效容量配置
        """
        cleaned_capacities = {}
        
        for worker_type, capacity in capacities.items():
            if not isinstance(worker_type, str) or not worker_type.strip():
                logger.warning(f"{source}: 跳过无效工种名称: {worker_type}")
                continue
                
            # 尝试转换为整数
            try:
                capacity_int = int(capacity)
                if capacity_int < 0:
                    logger.warning(f"{source}: 工种 '{worker_type}' 容量为负数({capacity_int})，设为0")
                    capacity_int = 0
                elif capacity_int > 1000:
                    logger.warning(f"{source}: 工种 '{worker_type}' 容量过大({capacity_int})，可能有误")
                
                cleaned_capacities[worker_type.strip()] = capacity_int
                
            except (ValueError, TypeError):
                logger.warning(f"{source}: 工种 '{worker_type}' 容量格式无效({capacity})，跳过")
                continue
        
        return cleaned_capacities
    
    def _generate_smart_default_capacities(
        self, 
        worker_requirements: Dict[str, Dict[str, int]]
    ) -> Dict[str, int]:
        """
        基于工种需求生成智能默认容量
        
        Args:
            worker_requirements: 工种需求字典
            
        Returns:
            智能默认容量配置
        """
        # 统计每种工种的最大单次需求和总需求
        worker_stats = {}
        
        for activity_id, requirements in worker_requirements.items():
            for worker_type, demand in requirements.items():
                if worker_type not in worker_stats:
                    worker_stats[worker_type] = {
                        "max_single_demand": 0,
                        "total_demand": 0,
                        "activity_count": 0
                    }
                
                worker_stats[worker_type]["max_single_demand"] = max(
                    worker_stats[worker_type]["max_single_demand"], 
                    demand
                )
                worker_stats[worker_type]["total_demand"] += demand
                worker_stats[worker_type]["activity_count"] += 1
        
        # 生成智能默认容量
        smart_capacities = {}
        for worker_type, stats in worker_stats.items():
            # 容量 = max(最大单次需求 * 1.2, 平均需求 * 2, 最小容量5)
            max_demand = stats["max_single_demand"]
            avg_demand = stats["total_demand"] / stats["activity_count"]
            
            smart_capacity = max(
                int(max_demand * 1.2),  # 最大单次需求的120%
                int(avg_demand * 2),    # 平均需求的200%
                5                       # 最小容量
            )
            
            smart_capacities[worker_type] = smart_capacity
            logger.info(f"智能默认容量 - {worker_type}: {smart_capacity} "
                       f"(最大需求:{max_demand}, 平均需求:{avg_demand:.1f})")
        
        return smart_capacities
    
    def _get_standard_default_capacities(self) -> Dict[str, int]:
        """
        获取标准默认工种容量配置
        
        Returns:
            标准默认容量字典
        """
        return {
            "钢筋工": 12,
            "泥工": 10,
            "架子工": 12,
            "模板工": 20,
            "电工": 2,
            "焊工": 2,
            "起重工": 2,
            "通用工人": 5,
            "挖掘工": 8,
            "混凝土工": 15,
            "装修工": 8,
            "管道工": 4,
            "瓦工": 6,
        }

    def _extract_worker_allocation(
        self, 
        project_data: Dict[str, Any]
    ) -> Dict[int, Dict[str, int]]:
        """
        提取工种分配结果
        
        Args:
            project_data: 项目数据
            
        Returns:
            工种分配字典 {activity_id: {worker_type: count}}
        """
        if self.solver is None:
            return {}
            
        worker_allocation = {}
        worker_requirements = project_data.get("worker_requirements", {})
        
        for activity in project_data["activities"]:
            activity_id = activity["id"]
            activity_id_str = str(activity_id)
            
            if activity_id_str in worker_requirements:
                worker_allocation[activity_id] = worker_requirements[activity_id_str].copy()
        
        return worker_allocation
    
    def _process_subdivision(
        self, 
        project_data: Dict[str, Any], 
        config: Dict[str, Any]
    ) -> Tuple[Dict[str, Any], Optional[Dict[str, Any]]]:
        """
        处理任务分区
        
        Args:
            project_data: 原始项目数据
            config: 配置参数
            
        Returns:
            (处理后的项目数据, 分区信息)
        """
        subdivision_config = config.get("subdivision_config", {})
        
        # 检查是否启用分区
        if not subdivision_config.get("enable_subdivision", False):
            return project_data, None
            
        subdivision_count = subdivision_config.get("subdivision_count", 2)
        
        # 检查是否有可分区的任务
        subdividable_activities = [
            act for act in project_data["activities"] 
            if act.get("can_subdivide", False)
        ]
        
        if not subdividable_activities:
            subdivision_info = {
                "enabled": False,
                "reason": "没有发现可分区的任务",
                "subdividable_count": 0,
                "subdivision_count": subdivision_count
            }
            return project_data, subdivision_info
        
        try:
            # 创建分区处理器
            processor = SubdivisionProcessor()
            
            # 转换为ProjectData对象进行分区处理
            from .simplified_data_models import ProjectData, Activity, Precedence
            
            # 创建Activity对象
            activities = []
            for act_data in project_data["activities"]:
                activity = Activity(
                    id=act_data["id"],
                    name=act_data["name"],
                    duration=act_data["duration"],
                    can_subdivide=act_data.get("can_subdivide", False),
                    worker_requirements=act_data.get("worker_requirements", {})
                )
                activities.append(activity)
            
            # 创建Precedence对象
            precedences = []
            for prec_data in project_data["precedences"]:
                precedence = Precedence(
                    from_activity=prec_data["from"],
                    to_activity=prec_data["to"],
                    dependency_type=prec_data["type"],
                    lag=prec_data["lag"]
                )
                precedences.append(precedence)
            
            # 创建ProjectData对象
            original_project_data = ProjectData(
                activities=activities,
                precedences=precedences,
                resources=project_data["resources"],
                resource_demands=project_data["resource_demands"]
            )
            
            # 执行分区处理
            subdivided_project_data = processor.subdivide_activities(
                original_project_data, 
                subdivision_count
            )
            
            # 转换回字典格式
            processed_data = {
                "activities": [
                    {
                        "id": act.id,
                        "name": act.name,
                        "duration": act.duration,
                        "can_subdivide": act.can_subdivide,
                        "worker_requirements": act.worker_requirements,
                        "subdivided": getattr(act, 'subdivided', False),
                        "original_duration": getattr(act, 'original_duration', act.duration)
                    }
                    for act in subdivided_project_data.activities
                ],
                "precedences": [
                    {
                        "from": prec.from_activity,
                        "to": prec.to_activity,
                        "type": prec.dependency_type,
                        "lag": prec.lag
                    }
                    for prec in subdivided_project_data.precedences
                ],
                "resources": subdivided_project_data.resources,
                "resource_demands": subdivided_project_data.resource_demands,
                "worker_requirements": project_data.get("worker_requirements", {})
            }
            
            # 更新工种需求（为分区后的任务）
            updated_worker_requirements = {}
            for activity in subdivided_project_data.activities:
                if activity.worker_requirements:
                    updated_worker_requirements[str(activity.id)] = activity.worker_requirements
            processed_data["worker_requirements"] = updated_worker_requirements
            
            # 生成分区信息
            subdivision_summary = processor.get_subdivision_summary(subdivided_project_data)
            subdivision_info = {
                "enabled": True,
                "subdivision_count": subdivision_count,
                "original_activities": len(project_data["activities"]),
                "processed_activities": len(processed_data["activities"]),
                "subdividable_count": len(subdividable_activities),
                "subdivided_count": subdivision_summary["subdivided_activities"],
                "subdivision_ratio": subdivision_summary["subdivision_ratio"]
            }
            
            return processed_data, subdivision_info
            
        except Exception as e:
            # 分区处理失败，返回原始数据
            subdivision_info = {
                "enabled": False,
                "error": f"分区处理失败: {str(e)}",
                "subdividable_count": len(subdividable_activities),
                "subdivision_count": subdivision_count
            }
            return project_data, subdivision_info


def solve_with_simplified_cpsat(
    project_data: Dict[str, Any], config: Dict[str, Any]
) -> SimplifiedSolverResult:
    """
    便捷函数：使用简化的CP-SAT求解项目调度问题

    Args:
        project_data: 标准化项目数据
        config: 求解配置参数

    Returns:
        求解结果对象
    """
    solver = SimplifiedCPSATSolver()
    return solver.solve(project_data, config)
